package com.dingwen.stumybplu.controller;

import com.dingwen.stumybplu.entity.User;
import com.dingwen.stumybplu.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试控制器 </br>
 * <p>注意： IService 的saveBath 方法会自动开启 mybatis 的 batch executor,不需要配置</p>
 *
 * @author dingwen
 * @date 2022/05/07
 */
@RestController
@RequestMapping("test")
@Slf4j
@RequiredArgsConstructor
public class TestController {


    /**
     * 用户服务
     */
    private final IUserService userService;

    /**
     * 需要存储的用户列表
     */
    LinkedList<User> users;


    /**
     * 批量插入的数据条数
     */
    Integer batchSize = 100000;

    /**
     * 多线程实现时的线程数
     */
    Integer threadSize = 10;


    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        users = new LinkedList<>();

        for (int i = 0; i < batchSize; i++) {
            User user = User.builder().createTime(LocalDateTime.now())
                    .build();
            users.add(user);
        }
    }


    /**
     * mybatis 实现批量插入：  批量插入: 100000条数据耗时：104389 （毫秒）
     */
    @GetMapping("mybatis")
    public void batchForMybatis() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        userService.saveBatch(users);
        stopWatch.stop();
        log.info("批量插入: {}条数据耗时：{} （毫秒）", batchSize, stopWatch.getTotalTimeMillis());
    }

    /**
     * 多线程实现批量插入: </br>
     * <ol>
     *     <li>批量插入: 100000条数据耗时：31474 （毫秒） (10线程)</li>
     *     <li>批量插入: 100000条数据耗时：35381 （毫秒）（20线程）</li>
     *     <li> 批量插入: 100000条数据耗时：45604 （毫秒）（5线程））</li>
     * </ol>
     */
    @GetMapping("thread")
    public void batchForThreads() {
        Long startTime = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(threadSize);
        for (int i = 0; i < threadSize; i++) {
            List<User> usersByThread = users.subList(batchSize / threadSize * i, batchSize / threadSize * (i + 1));

            Callable<Integer> task = () -> {
                userService.saveBatch(usersByThread);
                return 1;
            };

            executorService.submit(task);
        }
        executorService.shutdown();
        while (true) {
            if (executorService.isTerminated()) {
                log.info("批量插入: {}条数据耗时：{} （毫秒）", batchSize, System.currentTimeMillis() - startTime);
                break;
            }
        }

    }

}
